package controller;

import entity.Adesione;
import entity.Annuncio;
import entity.SitoAcquisti;
import entity.UtenteRegistrato;
import java.security.Security;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

/**
 * Metodi per inviare una e-mail
 * @author Ale
 */
@Stateless
@LocalBean
public class ControllerMail implements ControllerMailLocal {

    private static final String SMTP_HOST_NAME = "smtp.gmail.com";
    private static final String SMTP_PORT = "465";
    private static final String EMAIL_FROM_ADDRESS = "mail.shippingshare@gmail.com";
    private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";

    /**
     * Invia la mail che notifica che il creatore dell'annuncio ha controllato tutti gli articoli dell'adesione
     * @param iscritto iscritto all'annuncio
     * @param creatore creatore dell'annuncio
     * @param a adesione i cui articoli sono stati controllati
     */
    @Override
    public void sendMailArticoliControllati(UtenteRegistrato iscritto, UtenteRegistrato creatore, Adesione a) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", " + creatore.getNome() + " " + creatore.getCognome() + " ha controllato tutti gli articoli nella la tua adesione al suo annuncio per il sito " + a.getAnnuncio().getSito().getUrl() + ". Vieni su Shipping Share a vedere quali sono stati accettati!";
        String oggetto = "Articoli controllati";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail che notifica all'iscritto il rifiuto della sua adesione da parte del creatore
     * @param iscritto iscritto all'annuncio
     * @param creatore creatore dell'annuncio
     * @param adesione adesione rifiutata
     */
    @Override
    public void sendMailAdesioneRifiutata(UtenteRegistrato iscritto, UtenteRegistrato creatore, Adesione adesione) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", siamo spiacenti ma " + creatore.getNome() + " " + creatore.getCognome() + " ha rifiutato la tua adesione al suo annuncio per il sito " + adesione.getAnnuncio().getSito().getUrl() + ".";
        String oggetto = "Adesione rifiutata";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail che notifica all'iscritto l'accettazione della sua adesione da parte del creatore
     * @param iscritto iscritto all'annuncio
     * @param creatore creatore dell'annuncio
     * @param adesione adesione accettata
     */
    @Override
    public void sendMailAdesioneAccettata(UtenteRegistrato iscritto, UtenteRegistrato creatore, Adesione adesione) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", " + creatore.getNome() + " " + creatore.getCognome() + " ha accettato la tua adesione al suo annuncio per il sito " + adesione.getAnnuncio().getSito().getUrl() + "!";
        String oggetto = "Adesione accettata";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail al creatore dell'annuncio che notifica una nuova iscrizione al suo annuncio
     * @param iscritto nuovo iscritto all'annuncio
     * @param creatore creatore dell'annuncio
     * @param ad nuova adesione all'annuncio
     */
    @Override
    public void sendMailNuovaIscrizione(UtenteRegistrato iscritto, UtenteRegistrato creatore, Adesione ad) {
        String destinatario = creatore.getEmail().getIndirizzo();
        String testo = "Ciao " + creatore.getNome() + ", " + iscritto.getNome() + " " + iscritto.getCognome() + " ha aderito al tuo annuncio per il sito " + ad.getAnnuncio().getSito().toString() + ". Ricordati di accettare o rifiutare la sua adesione e gli articoli dell'adesione entro il " + formattaData(ad.getAnnuncio().getDataChiusura()) + ", giorno in cui l'annuncio sarà chiuso.";
        String oggetto = "Nuova iscrizione a un tuo annuncio";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail al creatore dell'annuncio che notifica una modifica nell'adesione di un iscritto
     * @param iscritto iscritto all'annuncio
     * @param creatore creatore dell'annuncio
     * @param ad adesione modificata
     */
    @Override
    public void sendMailIscrizioneModificata(UtenteRegistrato iscritto, UtenteRegistrato creatore, Adesione ad) {
        String destinatario = creatore.getEmail().getIndirizzo();
        String testo = "Ciao " + creatore.getNome() + ", " + iscritto.getNome() + " " + iscritto.getCognome() + " ha modificato la sua adesione al tuo annuncio per il sito " + ad.getAnnuncio().getSito().toString() + ". Ricordati di accettare o rifiutare i nuovi articoli dell'adesione entro il " + formattaData(ad.getAnnuncio().getDataChiusura()) + ", giorno in cui l'annuncio sarà chiuso.";
        String oggetto = "Iscrizione a un tuo annuncio modificata";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail che notifica che un moderatore ha cancellato un annuncio a cui il destinatario era iscritto
     * @param creatore creatore dell'annuncio
     * @param iscritto iscritto all'annuncio
     * @param a annuncio cancellato
     */
    @Override
    public void sendMailAnnuncioCancellatoAIscritto(UtenteRegistrato creatore, UtenteRegistrato iscritto, Annuncio a) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", l'annuncio a cui avevi aderito per il sito " + a.getSito().toString() + " di " + creatore.getNome() + " " + creatore.getCognome() + " è stato cancellato da un moderatore. Ti invitiamo a non inviare i soldi per gli articoli che avevi scelto o a farti rimborsare gli eventuali soldi già spediti.";
        String oggetto = "Annuncio cancellato";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail che notifica che il creatore ha cancellato un annuncio a cui il destinatario era iscritto
     * @param creatore creatore dell'annuncio
     * @param iscritto iscritto all'annuncio
     * @param a sito a cui si riferiva l'annuncio
     */
    @Override
    public void sendMailAnnuncioRimossoAIscritto(UtenteRegistrato creatore, UtenteRegistrato iscritto, SitoAcquisti a) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", l'annuncio a cui avevi aderito per il sito " + a.toString() + " di " + creatore.getNome() + " " + creatore.getCognome() + " è stato cancellato dal suo creatore. Ti invitiamo a non inviare i soldi per gli articoli che avevi scelto.";
        String oggetto = "Annuncio rimosso";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail che notifica che un moderatore ha cancellato un annuncio creato dal destinatario
     * @param creatore creatore dell'annuncio
     * @param a annuncio cancellato
     */
    @Override
    public void sendMailAnnuncioCancellatoACreatore(UtenteRegistrato creatore, Annuncio a) {
        String destinatario = creatore.getEmail().getIndirizzo();
        String testo = "Ciao " + creatore.getNome() + ", il tuo annuncio per il sito " + a.getSito().toString() + "  è stato cancellato da un moderatore. Ti invitiamo a rimborsare gli eventuali soldi già ricevuti dagli acquirenti il prima possibile.";
        String oggetto = "Annuncio cancellato";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail che notifica al creatore di un annuncio che un suo iscritto si è disiscritto
     * @param iscritto ex-iscritto
     * @param creatore creatore dell'annuncio
     * @param ad adesione cancellata
     */
    @Override
    public void sendMailUtenteDisiscritto(UtenteRegistrato iscritto, UtenteRegistrato creatore, Adesione ad) {
        String destinatario = creatore.getEmail().getIndirizzo();
        String testo = "Ciao " + creatore.getNome() + ", " + iscritto.getNome() + " " + iscritto.getCognome() + " si è disiscritto dal tuo annuncio per il sito " + ad.getAnnuncio().getSito().toString() + ".";
        String oggetto = "Utente disiscritto da un tuo annuncio";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail all'iscritto di un annuncio che notifica che il creatore ha chiuso in anticipo tale annuncio
     * @param creatore creatore dell'annuncio
     * @param iscritto iscritto all'annuncio
     * @param a annuncio chiuso in anticipo
     */
    @Override
    public void sendMailAnnuncioChiuso(UtenteRegistrato creatore, UtenteRegistrato iscritto, Annuncio a) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", l'annuncio a cui avevi aderito per il sito " + a.getSito().toString() + " di " + creatore.getNome() + " " + creatore.getCognome() + " è stato chiuso in anticipo dal suo creatore. Puoi quindi già inviare i soldi per gli articoli accettati. L'ordine avverrà comunque il giorno " + formattaData(a.getDataOrdine()) + ".";
        String oggetto = "Annuncio chiuso";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail all'iscritto di un annuncio che notifica che l'annuncio è stato chiuso perché scaduto
     * @param creatore creatore dell'annuncio
     * @param iscritto iscritto all'annuncio
     * @param a annuncio chiuso
     */
    public void sendMailAnnuncioScadutoIscritto(UtenteRegistrato creatore, UtenteRegistrato iscritto, Annuncio a) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", l'annuncio a cui avevi aderito per il sito " + a.getSito().toString() + " di " + creatore.getNome() + " " + creatore.getCognome() + " è stato chiuso come previsto. Controlla quali articoli sono stati accettati e invia i soldi. L'ordine avverrà il giorno " + formattaData(a.getDataOrdine()) + ".";
        String oggetto = "Annuncio chiuso";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail al creatore di un annuncio che notifica che l'annuncio è stato chiuso perché scaduto
     * @param creatore creatore dell'annuncio
     * @param a annuncio chiuso
     */
    public void sendMailAnnuncioScadutoCreatore(UtenteRegistrato creatore, Annuncio a) {
        String destinatario = creatore.getEmail().getIndirizzo();
        String testo = "Ciao " + creatore.getNome() + ", il tuo annuncio per il sito " + a.getSito().toString() + " è stato chiuso come previsto. Tutte le adesioni e gli articoli non esplicitamente accettati sono stati rifiutati. Dovrai fare l'ordine il giorno " + formattaData(a.getDataOrdine()) + ".";
        String oggetto = "Annuncio chiuso";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail a un utente che lo notifica che è stato bannato
     * @param u utente appena bannato
     */
    @Override
    public void sendMailUtenteBannato(UtenteRegistrato u) {
        String destinatario = u.getEmail().getIndirizzo();
        String testo = "Ciao " + u.getNome() + ", sei stato bannato da ShippingShare. Non potrai più accedere al nostro sito, e tutti i tuoi annunci e le tue adesioni sono state cancellate.";
        String oggetto = "Sei stato bannato";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail a un utente che lo notifica che è stato promosso a moderatore
     * @param u utente promosso a moderatore
     */
    @Override
    public void sendMailUtentePromossoModeratore(UtenteRegistrato u) {
        String destinatario = u.getEmail().getIndirizzo();
        String testo = "Ciao " + u.getNome() + ", complimenti! Sei stato promosso a moderatore di ShippingShare. Potrai gestire utenti ed annunci.";
        String oggetto = "Sei promosso a moderatore";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail a un utente che lo notifica che è stato declassato da moderatore a utente semplice
     * @param u utente declassato da moderatore
     */
    @Override
    public void sendMailUtenteDeclassatoDaModeratore(UtenteRegistrato u) {
        String destinatario = u.getEmail().getIndirizzo();
        String testo = "Ciao " + u.getNome() + ", siamo spiacenti ma sei stato declassato da moderatore a utente semplice di ShippingShare. Non potrai più gestire utenti ed annunci.";
        String oggetto = "Sei declassato a utente semplice";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail a un iscritto ad un annuncio che lo notifica che il creatore di tale annuncio è stato bannato e quindi l'annuncio cancellato
     * @param creatore creatore dell'annuncio, bannato
     * @param iscritto iscritto all'annuncio
     * @param sito sito a cui si riferiva l'annuncio
     */
    @Override
    public void sendMailBannatoAnnuncioCancellato(UtenteRegistrato creatore, UtenteRegistrato iscritto, SitoAcquisti sito) {
        String destinatario = iscritto.getEmail().getIndirizzo();
        String testo = "Ciao " + iscritto.getNome() + ", l'annuncio a cui avevi aderito per il sito " + sito.toString() + " di " + creatore.getNome() + " " + creatore.getCognome() + " è stato cancellato in quanto " + creatore.getNome() + " " + creatore.getCognome() + " è stato bannato. Ti invitiamo a non inviare i soldi per gli articoli che avevi scelto.";
        String oggetto = "Annuncio cancellato";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia una mail al creatore di un annuncio che lo notifica che un iscritto a tale annuncio è stato bannato e quindi la sua adesone cancellata
     * @param creatore creatore dell'annuncio
     * @param iscritto ex-iscritto all'annuncio, bannato
     * @param sito sito a cui si riferisce l'annuncio
     */
    @Override
    public void sendMailBannatoAdesioneCancellata(UtenteRegistrato creatore, UtenteRegistrato iscritto, SitoAcquisti sito) {
        String destinatario = creatore.getEmail().getIndirizzo();
        String testo = "Ciao " + creatore.getNome() + ", l'adesione di " + iscritto.getNome() + " " + iscritto.getCognome() + " al tuo annuncio per il sito " + sito.toString() + " è stata cancellata in quanto " + iscritto.getNome() + " " + iscritto.getCognome() + " è stato bannato. Ti invitiamo a restituire eventuali soldi già ricevuti.";
        String oggetto = "Adesione cancellata";

        sendMail(destinatario, testo, oggetto);
    }

    /**
     * Invia la mail che serve a verificare la validità dell'indirizzo e-mail fornito in fase di registrazione
     * @param utente l'utente da verificare
     */
    @Override
    public void sendMailVerifica(UtenteRegistrato utente) {
        String destinatario = utente.getEmail().getIndirizzo();
        String test = "Ciao " + utente.getNome() + ", "
                + "per confermare la tua iscrizione vai al seguente link: "
                + "http://localhost:8080/ShippingShareBisBis-war/Controller?action=validateUser&uid=" + utente.getUuid().toString()
                + " Grazie!";
        String oggetto = "Conferma la registrazione";
        sendMail(destinatario, test, oggetto);
    }

    /**
     * Invia la mail che serve per reimpostare la password nel caso l'utente la perdesse
     * @param utente utente che ja perso la password
     */
    @Override
    public void sendMailPwd(UtenteRegistrato utente) {
        String destinatario = utente.getEmail().getIndirizzo();
        String test = "Ciao " + utente.getNome() + ", "
                + "per cambiare al tua password vai al seguente link: "
                + "http://localhost:8080/ShippingShareBisBis-war/Controller?action=mailPassword&id="+utente.getId()+"&pwdId=" + utente.getUuid().toString()
                + " Grazie!";
        String oggetto = "Modifica la password";
        sendMail(destinatario, test, oggetto);
    }

    /**
     * Metodo generico per inviare una mail a un singolo destinatario
     * @param destinatario indirizzo e-mail del destinatario
     * @param testo contenuto della mail
     * @param oggetto oggetto della mail
     */
    protected void sendMail(String destinatario, String testo, String oggetto) {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        
        try {
            Properties props = new Properties();
            
            props.setProperty("mail.transport.protocol", "smtp");
            props.setProperty("mail.host", SMTP_HOST_NAME);
            props.put("mail.smtp.host", SMTP_HOST_NAME);
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.port", SMTP_PORT);
            props.put("mail.smtp.socketFactory.port", SMTP_PORT);
            props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
            props.put("mail.smtp.socketFactory.fallback", "false");
            props.setProperty("mail.smtp.quitwait", "false");

            Session session = Session.getInstance(props, new javax.mail.Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("mail.shippingshare@gmail.com", "sscsweb2011");
                }
            });

            Message msg = new MimeMessage(session);
            InternetAddress addressFrom = new InternetAddress(EMAIL_FROM_ADDRESS);
            InternetAddress addressTo = new InternetAddress(destinatario);
            
            msg.setFrom(addressFrom);
            msg.setRecipient(Message.RecipientType.TO, addressTo);
            msg.setSubject(oggetto);
            
            MimeBodyPart messagePart = new MimeBodyPart();
            MimeMultipart multipart = new MimeMultipart();
            
            multipart.addBodyPart(messagePart);
            
            messagePart.setText(testo, "utf-8");
            messagePart.setHeader("Content-Type", "text/plain; charset=\"utf-8\"");
            messagePart.setHeader("Content-Transfert-Encoding", "quoted-printable");
            
            msg.setContent(multipart);
            msg.setSentDate(new Date());
            
            Transport.send(msg);
        } catch (Exception ex) {
            Logger.getLogger(ControllerMail.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private String formattaData(GregorianCalendar d) {
        String[] mesi = {"gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"};
        return d.get(GregorianCalendar.DAY_OF_MONTH) + " " + mesi[d.get(GregorianCalendar.MONTH)] + " " + d.get(GregorianCalendar.YEAR);
    }
    
}
